﻿using CPAIS.Adapter;
using CPAIS.Model;
using CPAIS.Updater;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.SessionState;

namespace CPAIS.Web.AjaxHandlers
{
    public class HDPAnalysisHandler : AjaxHandler
    {
            public HDPAnalysisHandler(HttpContext context) : base(context) 
            { 
            }

            /// <summary>
            /// AJAX request:
            ///     HDPAnalysis
            /// 
            ///     
            /// Response:
            ///     None
            ///     
            /// </summary>
            #region Ajax Request HDPAnalysis

            public void HDPAnalysis()
            {
                string logName = Params[Constants.LogName];
                MLManager mlManager = Session[Constants.MLManager] as MLManager;

                HDPGibbsAdapter adapter = mlManager.GetHDPAdapter(logName);
                AnalysisUpdater updater = new AnalysisUpdater(Session, adapter,
                    int.Parse(Params[Constants.Iterations]));
                Session.Add(Constants.HDPAnalysisUpdater, updater);
                ThreadPool.QueueUserWorkItem(DoAnalysising, updater);
            }

            private class AnalysisUpdater : ProgressUpdater
            {
                public HttpSessionState Session { get; set; }
                public HDPGibbsAdapter Adapter { get; set; }
              
                public int Iterations { get; set; }

                public AnalysisUpdater(HttpSessionState session, HDPGibbsAdapter adapter, int iterations)
                {
                    this.Session = session;
                    this.Adapter = adapter;
                
                    this.Iterations = iterations;
                }

                protected override bool OnUpdateMessage(string message)
                {
                    if (Session[Constants.HDPAnalysisUpdater] != null)
                    {
                        return true;
                    }
                    return false;
                }

                protected override bool OnUpdateProgress(double progress)
                {
                    if (Session[Constants.HDPAnalysisUpdater] != null)
                    {
                        return true;
                    }
                    return false;
                }
            }

            private void DoAnalysising(object state)
            {
                AnalysisUpdater updater = state as AnalysisUpdater;
                HDPGibbsAdapter adapter = updater.Adapter;
                adapter.Execute(updater.Iterations, updater);
            }

            #endregion

            /// <summary>
            /// AJAX request:
            ///     CancelHDPAnalysis
            /// 
            /// Request Parameters:
            ///     logName
            /// 
            /// Response:
            ///     None
            /// </summary>
            #region Ajax Request CancelHDPAnalysis

            public void CancelHDPAnalysis()
            {
                Session.Remove(Constants.HDPAnalysisUpdater);
            }

            #endregion

            /// <summary>
            /// AJAX request:   
            ///     QueryHDPAnalysisProgress
            /// 
            /// Request Parameters:
            ///     logName
            /// 
            /// Response: 
            ///     QueryHDPAnalysisProgressPackage
            /// </summary>
            #region Ajax Request QueryHDPAnalysisProgress

            public void QueryHDPAnalysisProgress()
            {
                AnalysisUpdater updater = Session[Constants.HDPAnalysisUpdater] as AnalysisUpdater;
                QueryHDPAnalysisProgressPackage package;
                if(updater != null)
                    package = new QueryHDPAnalysisProgressPackage
                   {
                    state = updater.State.ToString(),
                    msg = updater.Message,
                    progress = updater.Progress
                    };
                else
                    package = new QueryHDPAnalysisProgressPackage
                    {
                        state = "Completed",
                        msg = "",
                        progress = 1.0
                    };
                switch (updater.State)
                {
                    case UpdateState.Failed:
                    case UpdateState.Completed:
                        Session.Remove(Constants.HDPAnalysisUpdater);
                        break;
                }
                WriteJson(package);
            }

            private class QueryHDPAnalysisProgressPackage
            {
                public string state { get; set; }
                public string msg { get; set; }
                public double progress { get; set; }
            }

            #endregion

            /// <summary>
            /// AJAX request:
            ///     GetHDPAnalysisSummary
            /// 
            /// Request Parameters:
            ///     logName
            /// 
            /// Response: 
            ///     GetHDPAnalysisSummaryPackage
            /// </summary>
            #region Ajax Request GetHDPAnalysisSummary

            public void GetHDPAnalysisSummary()
            {
                string logName = Params[Constants.LogName];
                MLManager mlManager = Session[Constants.MLManager] as MLManager;
                LogModel logModel = mlManager.GetLogModel(logName);
                GetHDPAnalysisSummaryPackage package = new GetHDPAnalysisSummaryPackage();
                if (logModel == null)
                {
                    package.state = false;
                    package.data = null;
                }
                else
                {
                    HDPGibbsAdapter adapter = mlManager.GetHDPAdapter(logName);
                    package.state = true;
                    package.data = new object[]
                {
                    new object[]{"Alpha", adapter.Alpha},
                    new object[]{"Beta", adapter.Beta},
                    new object[]{"Iterations", adapter.Iterations},
                    new object[]{"Document Size", adapter.DocumentSize},
                    new object[]{"Vocabulary Size", adapter.VocabularySize},
                    new object[]{"Topic Size", adapter.TopicSize},
                    new object[]{"Perplexity", adapter.Perplexity.ToString("0.###")},
                    new object[]{"KL Divergence", adapter.KLDivergence.ToString("0.###")},
                    new object[]{"Entropy", adapter.Entropy.ToString("0.###")}
                };
                }
                WriteJson(package);
            }

            private class GetHDPAnalysisSummaryPackage
            {
                public bool state { get; set; }
                public object[] data { get; set; }
            }

            #endregion

            /// <summary>
            /// AJAX request:
            ///     GetHDPDocData
            /// 
            /// Request Parameters:
            ///     logName
            /// 
            /// Response: 
            ///     TraceDataPackage
            /// </summary>
            #region Ajax Request GetHDPDocData

            public void GetHDPDocData()
            {
                string path = Params[Constants.LogName];
                int start = int.Parse(Params[Constants.Start]);
                int limit = int.Parse(Params[Constants.Limit]);

                MLManager mlManager = Session[Constants.MLManager] as MLManager;
                LogModel logModel = mlManager.GetLogModel(path);
                if (logModel != null)
                {
                    List<TraceData> traceData = new List<TraceData>();
                    foreach (var trace in logModel.Traces)
                    {
                        TraceData data = new TraceData
                        {
                            pid = trace.ID
                        };
                        traceData.Add(data);
                    }

                    TraceDataPackage package = new TraceDataPackage();
                    int count = traceData.Count;
                    int left = count - start;
                    package.total = count;
                    package.items = traceData.GetRange(start, limit <= left ? limit : left);
                    WriteJson(package);
                }
            }

            private class TraceData
            {
                public string pid { get; set; }
            }

            private class TraceDataPackage
            {
                public int total { get; set; }
                public List<TraceData> items { get; set; }
            }

            #endregion

            /// <summary>
            /// AJAX request:
            ///     GetHDPDocTopicProbability
            /// 
            /// Request Parameters:
            ///     logName
            ///     pid
            /// 
            /// Response: 
            ///     GetHDPDocTopicProbability
            /// </summary>
            #region Ajax Request GetHDPDocTopicProbability

            public void GetHDPDocTopicProbability()
            {
                string path = Params[Constants.LogName];
                string pid = Params[Constants.PID];
                MLManager mlManager = Session[Constants.MLManager] as MLManager;
                HDPGibbsAdapter adapter = mlManager.GetHDPAdapter(path);
                if (adapter != null && adapter.DocTopicAssoc.ContainsKey(pid))
                {
                    double[] probs = adapter.DocTopicAssoc[pid];
                    int length = probs.Length;
                    DocTopicProbabilityPackage[] package = new DocTopicProbabilityPackage[length];
                    for (int i = 0; i < length; i++)
                    {
                        package[i] = new DocTopicProbabilityPackage();
                        package[i].topicNo = "CP Pattern " + (i + 1).ToString();
                        package[i].probability = probs[i];
                    }
                    WriteJson(package);
                }
            }

            private class DocTopicProbabilityPackage
            {
                public string topicNo { get; set; }
                public double probability { get; set; }
            }

            #endregion

            /// <summary>
            /// AJAX request:
            ///     GetLDATopicData
            /// 
            /// Request Parameters:
            ///     logName
            /// 
            /// Response: 
            ///     TopicDataPackage
            /// </summary>
            #region Ajax Request GetHDPTopicData

            public void GetHDPTopicData()
            {
                string path = Params[Constants.LogName];

                MLManager mlManager = Session[Constants.MLManager] as MLManager;
                HDPGibbsAdapter adapter = mlManager.GetHDPAdapter(path);
                TopicDataPackage package = new TopicDataPackage { count = 0, items = null };
                if (adapter != null)
                {
                    var topics = adapter.TopicWordAssoc;
                    package.count = topics.Length;
                    package.items = new List<TopicData>();
                    foreach (var topic in topics)
                    {
                        TopicData topicData = new TopicData
                        {
                            prob = topic.Prob,
                            actions = new List<ActionData>()
                        };
                        foreach (var action in topic.Actions)
                        {
                            if (action.ActionProb >= 0.001)
                            {
                                topicData.actions.Add(new ActionData
                                {
                                    name = action.ActionType,
                                    prob = action.ActionProb
                                });
                            }
                        }
                        package.items.Add(topicData);
                    }
                }
                WriteJson(package);
            }

            private class ActionData
            {
                public string name { get; set; }
                public double prob { get; set; }
            }

            private class TopicData
            {
                public double prob;
                public List<ActionData> actions;
            }

            private class TopicDataPackage
            {
                public int count { get; set; }
                public List<TopicData> items { get; set; }
            }

            #endregion
        }
    
}